// Styles for a focus ring that animates outwards.

@use 'sass:map';
@use 'sass:list';
@use 'sass:meta';

@use '@material/theme/keys';
@use '@material/theme/validate';
@use '@material/shape/shape';
@use './focus-ring-shared-theme';

$_custom-property-prefix: 'focus-ring-outward';

$default-outward-theme: focus-ring-shared-theme.$default-shared-theme;
$default-outward-theme: map.merge(
  focus-ring-shared-theme.$default-shared-theme,
  (
    focus-ring-shared-theme.$ring-offset-key: 2px,
    // Target shape can be provided as a single value, or as a list with
    // 1-4 values where each value would correspond to border radius of one
    // or more corners.
    focus-ring-shared-theme.$target-shape-key: 0px,
  )
);

/// Generates CSS custom properties that are consumed by the focus ring styles.
/// Intended to be used directly by Material Design customers, as the only
/// formally supported means of customizing the focus ring.
///
/// @param {Map} $theme - A map with one or more of the keys of $default-outward-theme.
@mixin theme($theme) {
  $theme: validate.theme($default-outward-theme, $theme);
  $theme: _expand-target-shape-value($theme);
  @include keys.declare-custom-properties($theme, $_custom-property-prefix);
}

@mixin theme-styles($theme: $default-outward-theme) {
  $theme: validate.theme-styles($default-outward-theme, $theme);
  $theme: _expand-target-shape-value($theme);
  $theme: keys.create-theme-vars($theme, $_custom-property-prefix);

  $ring-color: map.get($theme, focus-ring-shared-theme.$ring-color-key);
  $ring-offset: map.get($theme, focus-ring-shared-theme.$ring-offset-key);
  $track-width: map.get($theme, focus-ring-shared-theme.$track-width-key);
  $target-shape-start-start: map.get(
    $theme,
    '#{focus-ring-shared-theme.$target-shape-key}-start-start'
  );
  $target-shape-start-end: map.get(
    $theme,
    '#{focus-ring-shared-theme.$target-shape-key}-start-end'
  );
  $target-shape-end-end: map.get(
    $theme,
    '#{focus-ring-shared-theme.$target-shape-key}-end-end'
  );
  $target-shape-end-start: map.get(
    $theme,
    '#{focus-ring-shared-theme.$target-shape-key}-end-start'
  );

  /// Mold the focus ring to the target shape.
  /// See the diagram for insights into why the border-radius calc is needed:
  /// http://screen/9J9CzpCxJxxDHCb.png
  border-start-start-radius: calc($target-shape-start-start + $ring-offset);
  border-start-end-radius: calc($target-shape-start-end + $ring-offset);
  border-end-end-radius: calc($target-shape-end-end + $ring-offset);
  border-end-start-radius: calc($target-shape-end-start + $ring-offset);
  inset: calc(-1 * $ring-offset);
  box-shadow: 0 0 0 $track-width $ring-color;
  // HCM ignores box-shadow, so a transparent outline is added to ensure
  // focus ring is shown in HCM.
  outline: $track-width solid transparent;

  @include _focus-ring-animation-keyframes($theme);
  @include focus-ring-shared-theme.focus-ring-animation(
    $grow-animation-name: focus-ring-outward-grows,
    $shrink-animation-name: focus-ring-outward-shrinks
  );
}

@mixin _focus-ring-animation-keyframes($theme) {
  $ring-color: map.get($theme, focus-ring-shared-theme.$ring-color-key);

  $start-border-width: 0;
  $midpoint-border-width: 8px;

  @keyframes focus-ring-outward-grows {
    from {
      box-shadow: 0 0 0 $start-border-width $ring-color;
    }
    to {
      box-shadow: 0 0 0 $midpoint-border-width $ring-color;
    }
  }

  @keyframes focus-ring-outward-shrinks {
    from {
      box-shadow: 0 0 0 $midpoint-border-width $ring-color;
    }
  }
}

/// Replaces target shape value or list provided in theme with four key-value
/// pairs corresponding to four corners' border radiuses.
///
/// @example:
/// _expand-target-shape-value(('target-shape': 4px)) =>
///  (
///    'target-shape-start-start': 4px,
///    'target-shape-start-end': 4px,
///    'target-shape-end-end': 4px,
///    'target-shape-end-start': 4px
///  )
///
@function _expand-target-shape-value($theme) {
  @return shape.resolve-theme(
    $theme,
    meta.get-function('resolver', $module: 'shape'),
    focus-ring-shared-theme.$target-shape-key
  );
}
